#pragma once
#include "interfaces.h"
#include "d3d9util.h"
#include "SceneNode.h"
#include "Geometry.h"
#include "EventManager.h"

typedef std::map<ActorId, std::shared_ptr<ISceneNode2D>> Scene2DActorMap;

class Camera2D : public SceneNode2D
{
public:
	Camera2D(Area const &area)
		: SceneNode2D("Camera", &area.GetPosition(), &area.GetSize()),
			m_area(area)
	{
	}

	virtual bool VIsVisible(Scene2D * pScene) { return true; }

	Mat4x4 GetWorldView(Scene2D* pScene);
	const Area &GetViewArea() const { return m_area; }

protected:
	Area m_area;
};

class RootNode2D : public SceneNode2D
{
public:
	RootNode2D();
	virtual ~RootNode2D() { }

	virtual bool VAddChild(std::shared_ptr<ISceneNode2D> kid);
	virtual bool VRemoveChild(ActorId id);
	virtual HRESULT VRenderChildren(Scene2D *pScene);
	virtual bool VIsVisible(Scene2D * pScene) { return true; }
};

class SpriteNode : public SceneNode2D
{
public:
	SpriteNode(const TCHAR* file, const Vec2 *pos, const Vec2 *size, double orientation = 0, ActorId id = 0);

	virtual ~SpriteNode();

	virtual HRESULT VRestore(Scene2D* pScene);
	virtual bool VIsVisible(Scene2D * pScene);
	virtual HRESULT VRender(Scene2D *pScene);

	virtual void VSetSize(const Vec2& size) override { SceneNode2D::VSetSize(size); UpdateScale(); }

protected:
	void UpdateScale();

	const TCHAR* m_filename;
	IDirect3DTexture9* m_pTexture;
	D3DXIMAGE_INFO info;
};

class Scene2D : public IScreenElement
{
public:
	virtual HRESULT VRestore() override;
	virtual HRESULT VRender() override;
	virtual void VUpdate(double deltaSecs) override;
	virtual int VGetZOrder() const override { return m_zOrder; }
	virtual void VSetZOrder(int const zOrder) override { m_zOrder = zOrder; }
	virtual bool VIsVisible() const override { return m_bVisible; }
	virtual void VSetVisible(bool visible) override { m_bVisible = visible; }

	void SetCamera(const std::shared_ptr<Camera2D>& camera) { m_pCamera = camera; }
	const std::shared_ptr<Camera2D> GetCamera() const { return m_pCamera; }

	bool AddChild(std::shared_ptr<ISceneNode2D> kid, ActorId id = 0);
	bool RemoveChild(ActorId id);
	std::shared_ptr<ISceneNode2D> FindActor(ActorId id);

	void PushAndSetMatrix(const Mat4x4& toWorld);
	void PopMatrix();
	const Mat4x4 *GetTopMatrix() { return static_cast<const Mat4x4 *>(m_pMatrixStack->GetTop()); }

	Scene2D();
	virtual ~Scene2D();

	void RegisterEvents();
	void OnNewRenderComponent(IEventPtr pEvent);
	void OnMoveActor(IEventPtr pEvent);
	
protected:
	ID3DXMatrixStack *m_pMatrixStack;
	Scene2DActorMap m_actorMap;
	std::shared_ptr<SceneNode2D> m_pRoot;
	std::shared_ptr<Camera2D> m_pCamera;
	bool m_bVisible;
	int m_zOrder;
};